﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace MadProps
{
    public abstract class PropModel : IHavePropId, INotifyPropertyChanged, MadProps.Templating.ISelfTemplatingDataContext
    {
        public class PropModelMetadata
        {
            readonly PropId propId;
            internal PropModelMetadata(PropId propId)
            {
                this.propId = propId.ThrowIfNull("propId");
            }

            public object this[string metadataKey]
            {
                get
                {
                    return Definition.MetadataStore.GetValue(propId, metadataKey,
                        System.Windows.DependencyProperty.UnsetValue);
                }
            }
        }

        public IProp Prop { get; private set; }
        public PropId PropId { get { return Prop.PropId; } }
        public Validation.ValidationModel Validation { get; private set; }
        public PropModelMetadata Meta { get; private set; }

        readonly Templating.SelfTemplatingImpl selfTemplating;

        public PropModel(Composition composition, IProp prop)
        {
            this.Prop = prop.ThrowIfNull("prop");
            this.Validation = MadProps.Validation.ValidationModelFactory.Build(composition, prop);

            this.Meta = new PropModelMetadata(prop.PropId);

            Prop.PropChanged += (s, e) => PropertyChanged.Raise(this, "Value");

            this.selfTemplating = new Templating.SelfTemplatingImpl(composition, prop);
        }

        public object Value
        {
            get { return Prop.Value; }
            set { Prop.Value = value; }
        }

        public string DisplayName
        {
            get { return MadProps.Meta.DisplayName.Of(this); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        System.Windows.DataTemplate Templating.ISelfTemplatingDataContext.SelectTemplate(System.Windows.Controls.Control target)
        {
            return selfTemplating.SelectTemplate(target);
        }
    }

    public class PropModel<T> : PropModel
    {
        public PropModel(Composition composition, IProp prop)
            : base(composition, prop)
        {
        }

        // It's easier to expose the Value as the actual underlying type
        // than to mess around with more type descriptors.
        // We need WPF to know that it should try to convert to T.
        // (for example, TextBox bound to int)
        public new T Value
        {
            get { return (T)Prop.Value; }
            set { Prop.Value = value; }
        }
    }
}
